import time

import keyboard

from enums.WidgetType import WidgetType
import pyautogui
import threading
import os.path as ospath
from config import config, ScriptList
from event import Event
from util.OCR import OCR
from util import ImageUtil
from enums.KeyboardInputType import KeyboardInputType
from enums.ConditionType import ConditionType
from widgets.scriptWidgets.condition.VarCompare import VarCompare
import pyperclip
from plat.Platform import Platform


class Runner:
    def __init__(self):
        self.runThread = None
        self._isRunning = False
        self._variables = {}
        self.esc_key = 'esc'

    def onESC(self, event):
        print("ESC key was pressed. stop script.")
        self.stop()

    def run(self, scripts):
        if self.isRunning:
            print('it is running, dont running together')
            return

        # 监听ESC键
        keyboard.on_press_key(self.esc_key, self.onESC)

        self.runThread = threading.Thread(target=self._run, args=(scripts,))
        self._isRunning = True
        self.runThread.start()

    def stop(self):
        self._isRunning = False
        # 抑制错误
        try:
            keyboard.unhook_key(self.esc_key)
        except KeyError:
            pass
        
        self.onStop()

    def onStop(self):
        pass

    def _run(self, scripts, parentScript=None):
        for script in scripts:
            try:
                if not self.isRunning:
                    break

                if 'enable' in script and (not script['enable']):
                    continue

                scriptType = script['type']
                if scriptType == WidgetType.WAIT.value:
                    pyautogui.sleep(round(script['time'] / 1000, 3))
                elif scriptType == WidgetType.WAIT_TEXT.value:
                    self.doWaitText(script)
                elif scriptType == WidgetType.WAIT_PIC.value:
                    self.doWaitPic(script)
                elif scriptType == WidgetType.CLICK_POS.value:  # 点击位置
                    pyautogui.click(script['x'], script['y'], button=script['button'])
                elif scriptType == WidgetType.DOUBLE_CLICK_POS.value:
                    pyautogui.doubleClick(script['x'], script['y'], button=script['button'], interval=0.2)
                elif scriptType == WidgetType.LONG_PRESS_POS.value:
                    scriptTime = round(script['time'] / 1000, 2)
                    self.longPress(script['x'], script['y'], script['button'], scriptTime)
                elif scriptType == WidgetType.VARIABLE_SET.value:
                    self.variables[script['name']] = script['value']
                elif scriptType == WidgetType.CLICK_TEXT.value:  # 点击文字
                    self.clickText(script)
                elif scriptType == WidgetType.DOUBLE_CLICK_TEXT.value:
                    self.clickText(script)
                elif scriptType == WidgetType.LONG_PRESS_TEXT.value:
                    self.clickText(script)
                elif scriptType == WidgetType.CLICK_PIC.value:  # 点击图片
                    self.ClickPic(script)
                elif scriptType == WidgetType.DOUBLE_CLICK_PIC.value:
                    self.ClickPic(script)
                elif scriptType == WidgetType.LONG_PRESS_PIC.value:
                    self.ClickPic(script)
                elif scriptType == WidgetType.DRAG.value:  # 拖拽
                    scriptTime = round(script['time'] / 1000, 2)
                    pyautogui.mouseDown(script['from_x'], script['from_y'], button=script['button'])
                    pyautogui.moveTo(script['to_x'], script['to_y'], duration=scriptTime)
                    pyautogui.mouseUp()
                elif scriptType == WidgetType.INPUT_TEXT.value:  # 输入文字
                    pyperclip.copy(script['text'])
                    pyautogui.hotkey('ctrl' if Platform.isWindows() else 'command', 'v')
                elif scriptType == WidgetType.INPUT_KEYBOARD.value:  # 键盘输入
                    if script['input_type'] == KeyboardInputType.ALONE.value:
                        pyautogui.press(script['keys'])
                    else:
                        for key in script['keys']:
                            pyautogui.keyDown(key)

                        for key in script['keys']:
                            pyautogui.keyUp(key)
                elif scriptType == WidgetType.CALL_SCRIPT.value:  # 调用脚本
                    scriptBeCall = ScriptList.getById(script['script_id'])
                    self._run(scriptBeCall['content'], script)
                elif scriptType == WidgetType.IF.value:
                    self.doIf(script)
                elif scriptType == WidgetType.FOR.value:
                    for c in range(script['count']):
                        result = self._run(script['sub_script'], script)
                        if result == 'break':
                            break
                elif scriptType == WidgetType.WHILE.value:
                    self.doWhile(script)
                elif scriptType == WidgetType.BREAK.value:
                    return 'break'
                elif scriptType == WidgetType.CONTINUE.value:
                    return 'continue'
            except ValueError as e:
                continue

        if parentScript is not None:
            return

        self.stop()
        Event.dispatch('script_stop', scripts)

    @property
    def isRunning(self):
        return self._isRunning

    @property
    def variables(self):
        return self._variables

    def longPress(self, x, y, button, pressTime):
        pyautogui.mouseDown(x, y, button=button)
        pyautogui.sleep(pressTime)
        pyautogui.mouseUp(button=button)

    def findText(self, script):
        return OCR.screenTextPos(
            script['text'],
            region=(script['x'], script['y'], script['x'] + script['width'], script['y'] + script['height'])
        )

    def doWaitText(self, script):
        textPos = None
        while textPos is None:
            textPos = self.findText(script)
            time.sleep(0.5)

    def doWaitPic(self, script):
        imgPos = None
        while imgPos is None:
            imgPos = self.findPic(script)
            time.sleep(0.5)

    def doIf(self, script):
        conditionType = script['condition_type']
        conditionInfo = script['condition_info']
        if conditionType == ConditionType.VAR_COMPARE.value:
            if VarCompare.verify(conditionInfo, self.variables):
                self._run(script['sub_script'], script)
        elif conditionType == ConditionType.TEXT_CONTAIN.value:
            textPos = self.findText(conditionInfo)
            if textPos is not None:
                self._run(script['sub_script'], script)
        elif conditionType == ConditionType.PIC_CONTAIN.value:
            imgPos = self.findPic(conditionInfo)
            if imgPos is not None:
                self._run(script['sub_script'], script)

    def doWhile(self, script):
        conditionType = script['condition_type']
        conditionInfo = script['condition_info']
        if conditionType == ConditionType.VAR_COMPARE.value:
            while VarCompare.verify(conditionInfo, self.variables):
                result = self._run(script['sub_script'], script)
                if result == 'break':
                    break
        elif conditionType == ConditionType.TEXT_CONTAIN.value:
            textPos = self.findText(conditionInfo)
            while textPos is not None:
                result = self._run(script['sub_script'], script)
                if result == 'break':
                    break
        elif conditionType == ConditionType.PIC_CONTAIN.value:
            imgPos = self.findPic(conditionInfo)
            while imgPos is not None:
                result = self._run(script['sub_script'], script)
                if result == 'break':
                    break

    def clickText(self, script):
        textPos = self.findText(script)
        if textPos is None:
            return

        scriptType = script['type']
        x = script['x'] + ((textPos[0][0] + textPos[1][0]) / 2)
        y = script['y'] + ((textPos[0][1] + textPos[2][1]) / 2)
        if scriptType == WidgetType.CLICK_TEXT.value:
            pyautogui.click(x, y, button=script['button'])
        elif scriptType == WidgetType.DOUBLE_CLICK_TEXT.value:
            pyautogui.doubleClick(x, y, button=script['button'], interval=0.2)
        elif scriptType == WidgetType.LONG_PRESS_TEXT.value:
            scriptTime = round(script['time'] / 1000, 2)
            self.longPress(x, y, script['button'], scriptTime)

    def findPic(self, script):
        grabImgPath = ospath.join(config.SCRIPT_PIC_RECOGNITION_PIC_PATH, 'temp.png')
        ImageUtil.grab(
            grabImgPath,
            (script['x'], script['y'], script['x'] + script['width'], script['y'] + script['height'])
        )

        return ImageUtil.findImg(grabImgPath, script['pic'])

    def ClickPic(self, script):
        imgPos = self.findPic(script)
        if imgPos is None:
            return

        imgRect = imgPos['rectangle']
        scriptType = script['type']
        x = script['x'] + ((imgRect[0][0] + imgRect[2][0]) / 2)
        y = script['y'] + ((imgRect[0][1] + imgRect[3][1]) / 2)
        if scriptType == WidgetType.CLICK_PIC.value:
            pyautogui.click(x, y, button=script['button'])
        elif scriptType == WidgetType.DOUBLE_CLICK_PIC.value:
            pyautogui.doubleClick(x, y, button=script['button'], interval=0.2)
        elif scriptType == WidgetType.LONG_PRESS_PIC.value:
            scriptTime = round(script['time'] / 1000, 2)
            self.longPress(x, y, script['button'], scriptTime)
